<?php namespace xlx\lib;

use \Workerman\Events\EventInterface;
use \React\Promise\Deferred;

class LocalActor implements \xlx\lib\ActorInterface
{
    public $pid = null;
    public $mailbox=[];
    public $receive=[];
    public function __construct($pid)
    {
        // if (empty($pid)) {
        //     $pid = spl_object_hash($this);// \microtime(true);
        // }
        // $this->pid = $pid;
        $this->pid = $pid;
        $this->mailbox = new ArrayQueue();
        $this->receive = new CircleQueue();
    }
    public function __destruct()
    {
        // unset($this->mailbox[$this->self()]);
        // unset($this->receive[$this->self()]);
    }
    public function self()
    {
        return $this->pid;
    }
    public function receive($receive = null/*(data)=>{ data };*/)
    {
        $defer = new \React\Promise\Deferred;
        $defer->fn = $receive??function ($data) {
            if (!\is_array($data)) {
                return $data;
            }
        };
        $k = $this->receive->push($defer);
        foreach ($this->mailbox as $i => $msg) {
            if ($this->notify( $k, $defer, $i, $msg )) {
                break;
            }
        }
        return $defer->promise();
    }
    public function send($to, $data)
    {
        if (!isset($to->mailbox) or !isset($to->receive)) {
            $to = \xlx\WeakRef::take($to);
        }
        $i = $to->mailbox->push($data);
        foreach ($to->receive as $k => $defer) {
            if ($to->notify($k, $defer, $i, $data )) {
                break;
            }
        }
    }
    public function notify($k, $defer, $i, $msg)
    {
        try {
            if (null!==($data = \call_user_func($defer->fn, $msg))) {
                $this->mailbox->splice($i);
                $this->receive->splice($k);
                $defer->resolve($data);
                return true;
            }
        } catch (\Throwable $e) {
            $defer->reject($e); 
            return true;
        }
    }
    protected static function exists($to)
    {
        return !!\xlx\WeakRef::take($to);
    }
}
